package com.amkai.aes.webservice.binary.objecthandler.casehistory;

import java.io.Serializable;
import java.util.Collection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;

import com.amkai.aes.aescommon.service.binary.job.casehistory.CaseHistorySyncJob;
import com.amkai.aes.aescommon.service.scheduling.AppointmentStatusChangeResult;
import com.amkai.aes.generatedbeans.cdmcasehistory.CdmCaseHistory;
import com.amkai.aes.generatedbeans.cdmcasehistory.logdetails.phase.ExtendedDepartmentLog;
import com.amkai.aes.generatedbeans.cdmcasehistory.logdetails.phase.PatDepartmentLog;
import com.amkai.aes.generatedbeans.organization.Department;
import com.amkai.aes.generatedbeans.passport.Passport;
import com.amkai.aes.generatedbeans.pmcase.PmCaseStatusKind;
import com.amkai.aes.generatedbeans.scheduling.AbstractAppointment;
import com.amkai.aes.generatedbeans.scheduling.resources.AppointmentTypeKind;
import com.amkai.aes.server.casehistory.CaseHistoryServerUtils;
import com.amkai.aes.server.domaincommiter.casehistory.CaseHistoryLoader;
import com.amkai.aes.server.manager.CdmCaseHistoryManager;
import com.amkai.aes.server.session.ServiceSessionManager;
import com.amkai.aes.webservice.binary.JobObjectHandler;
import com.amkai.common.extensions.hibernate.config.SiteManager;
import com.amkai.common.extensions.hibernate.config.manager.SessionManager;

public class CaseHistorySyncJobHandler implements JobObjectHandler<CaseHistorySyncJob, Serializable, Boolean> {

	private static final Log log = LogFactory.getLog(CaseHistorySyncJobHandler.class);
	private static final String CASE_HISTORY_BY_PMCASE = "FROM CdmCaseHistory history WHERE history.pmCase.id = :caseid";

	protected CdmCaseHistory downloadCaseHistory(SessionManager sm, Long caseId) throws Exception {
		CdmCaseHistory result = null;

		if (caseId != null && caseId > 0) {
			try {
				if (caseId != null) {
					Query query = sm.execute(CASE_HISTORY_BY_PMCASE);
					query.setParameter("caseid", caseId);

					result = (CdmCaseHistory) query.uniqueResult();
					if (result != null) {
						CaseHistoryLoader caseHistoryLoader = new CaseHistoryLoader();
						result = caseHistoryLoader.load(sm, result);
					}

					sm.clear();
				}
			} catch (Exception e) {
				log.error("Case History Sync Job - Download Case History.", e);
				e.printStackTrace();
				throw e;
			}
		}

		return result;
	}

	protected void processPATAppointment(SessionManager sm, CdmCaseHistory caseHistory, AppointmentStatusChangeResult changeResult) throws Exception {
		ExtendedDepartmentLog log = getDepartmentLog(caseHistory, changeResult.getAbstractAppointment());
		if (log != null) {
			CaseHistoryServerUtils.deleteExtendedDepartmentLog(sm, log);
		}
	}

	protected ExtendedDepartmentLog getDepartmentLog(CdmCaseHistory caseHistory, AbstractAppointment app) {
		if (caseHistory != null && app != null && app.getId() != null) {
			for (PatDepartmentLog log : caseHistory.getPatDepartmenLogs()) {
				if (log != null && log.getAbstractAppointment() != null && log.getAbstractAppointment().getId() != null && log.getAbstractAppointment().getId().equals(app.getId())) {
					return log;
				}
			}
		}

		return null;
	}

	// KKORNEL: AES-16306 - moduleDepartment, runtimePassport parameters added
	protected void processAppointmentStatusChangeResult(SessionManager sm, CdmCaseHistory caseHistory, AppointmentStatusChangeResult changeResult, Department moduleDepartment, Passport runtimePassport) throws Exception {
		if (changeResult != null && needProcessingAppointment(changeResult.getAbstractAppointment(), changeResult.getNewStatus())) {
			switch (changeResult.getAbstractAppointment().getAppointmentKind()) {
			case PAT:
				processPATAppointment(sm, caseHistory, changeResult);
				break;
			case OR:
				new CdmCaseHistoryManager().deleteCaseHistory(sm, caseHistory, moduleDepartment, runtimePassport);
				break;
			}
		}
	}

	protected boolean needProcessingAppointment(AbstractAppointment app, PmCaseStatusKind newStatus) {
		if (app != null && app.getStatus() != null && newStatus != null) {
			
			switch (newStatus) {
			case CANCELED:
				if (app.getStatus().equals(PmCaseStatusKind.PENDING)) {
					return false;
				} 
				
				if (app.getAppointmentKind().equals(AppointmentTypeKind.PAT)) {
					return true;
				}
				break;
				
			case PENDING:
				if (app.getAppointmentKind().equals(AppointmentTypeKind.OR)) {
					return true;
				}
				break;
			}
			
		}
		
		return false;
	}
	
	protected boolean needProcessingList(Collection<AppointmentStatusChangeResult> changeResults) {
		if (changeResults != null) {
			for (AppointmentStatusChangeResult changeResult : changeResults) {
				if (needProcessingAppointment(changeResult.getAbstractAppointment(), changeResult.getNewStatus())) {
					return true;
				}
			}
		}
		
		return false;
	}
	
	@Override
	public Boolean process(CaseHistorySyncJob job, Serializable object) throws Exception {
		Boolean result = false;
		if (job != null && needProcessingList(job.getChangeResults())) {

			SessionManager sm = SiteManager.Start();
			sm.openSession();
			try {
				CdmCaseHistory caseHistory = downloadCaseHistory(sm, job.getChangeResults().iterator().next().getPmCase().getId());
				if (caseHistory != null) {
					sm.openTransaction();
					try {

						for (AppointmentStatusChangeResult changeResult : job.getChangeResults()) {
							// KKORNEL: AES-16306
							processAppointmentStatusChangeResult(sm, caseHistory, changeResult, job.getModuleDepartment(), ServiceSessionManager.getConnection().getRuntimePassport());
						}

						//sm.saveRAD(caseHistory);

						sm.commitTransaction();

						result = true;
					} catch (Exception exception) {
						result = false;
						log.error("Case History Sync Job - Process.", exception);
						exception.printStackTrace();
						sm.rollbackTransaction();
						throw exception;
					}
				}
			} finally {
				sm.closeSession();
			}
			
		}

		return result;
	}

}

